/********************************************************************** 
 * FILE		: ClassUtilTools.java					
 *			
 * AUTHOR   : kloyf		
 * 
 * DATE		: 2011-6-19
 * 									
 * REASON	: CREATE  
 *            							
 * VERSION  ：0.0.1
 *
 ***********************************************************************/
package com.common.util.clazz;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.common.util.BaseRegex;
import com.common.util.string.StringUtilTools;

/**
 * 对象工具类
 * 
 * @author kloyf
 * @version 0.0.1
 */
public class ClassUtilTools extends AbstractClassUtil {

	private static Class<ClassUtilTools> clazz = ClassUtilTools.class;

	/**
	 * <pre>
	 * 功能描述：根据类名获取指定的类
	 * </pre>
	 * 
	 * @param cls
	 *            Class对象。
	 * @return Object 返回一个实例化的类。
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Object getEntityInstance(Class cls) {
		Constructor ct;
		Object obj = null;
		try {
			ct = cls.getConstructor();
			// 获取指定对象的实例
			obj = ct.newInstance();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}

		return obj;
	}

	/**
	 * 根据类名获取指定的Class
	 * 
	 * @param className
	 *            class名。
	 * @return Class 返回一个Class对象。
	 */
	@SuppressWarnings("rawtypes")
	public static Class getEntityClass(String className) {
		Class cls = null;
		try {
			cls = Class.forName(className);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} // 加载指定的Java类
		return cls;
	}

	/**
	 * <pre>
	 * 把Map<String,Object>里的数据复制到Bean对象里。
	 * Map里的数据的键值必须在Bean对象里属性名和类型一至，且属性至少有set方法，否则无法复制。
	 * </pre>
	 * 
	 * @param sourMap
	 *            复制的源数据Map
	 * @param tarObj
	 *            复制后的目标对象。
	 * @return Object 返回复制后的目标对象
	 */
	public static Object copyBean(Map<?, ?> sourMap, Object tarObj) {
		Method[] methods = getObjectMethods(tarObj);
		Iterator<?> keys = sourMap.keySet().iterator();
		while (keys.hasNext()) {
			String key =  (String) keys.next();
			for (Method method : methods) {
				if (method.getName().equals("set" + StringUtilTools.toUpperCaseFirstOne(key))) {
					try {
						Object object = convertFromString(tarObj.getClass().getDeclaredField(key).getType(), String.valueOf(sourMap.get(key)));
						// method.invoke(tarObj, object);
						setMethodInvoke(tarObj, key, object);
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (SecurityException e) {
						e.printStackTrace();
					} catch (NoSuchFieldException e) {
						e.printStackTrace();
					}
				}
			}
		}

		return tarObj;
	}

	/**
	 * <pre>
	 * 把两个bean对象里相同的属性进行复制。
	 * 两个bean对象里，能够复制的属性名和类型得一致，否则无法复制。
	 * </pre>
	 * 
	 * @param sourObj
	 *            复制的源对象
	 * @param tarObj
	 *            复制后的目标对象。
	 * @return Object 返回复制后的目标对象
	 */
	public static Object copyBean(Object sourObj, Object tarObj) {
		Method[] method1 = getObjectMethods(sourObj);
		Method[] method2 = getObjectMethods(tarObj);
		String methodName1;
		String methodFix1;
		String methodName2;
		String methodFix2;
		for (Method sourMethod : method1) {
			methodName1 = sourMethod.getName();
			methodFix1 = methodName1.substring(3, methodName1.length());
			if (methodName1.startsWith("get")) {
				for (Method tarMethod : method2) {
					methodName2 = tarMethod.getName();
					methodFix2 = methodName2.substring(3, methodName2.length());
					if (methodName2.startsWith("set")) {
						if (methodFix2.equals(methodFix1)) {
							Object[] objs1 = new Object[0];
							Object[] objs2 = new Object[1];
							try {
								// 激活sourObj的相应的get的方法，objs1数组存放调用该方法的参数,此例中没有参数，该数组的长度为0
								objs2[0] = sourMethod.invoke(sourObj, objs1);
								// 激活tarObj的相应的set的方法，objs2数组存放调用该方法的参数
								tarMethod.invoke(tarObj, objs2);
							} catch (Exception e) {
								debug(clazz, e);
							}
							continue;
						}
					}
				}
			}
		}
		return tarObj;
	}

	/**
	 * 调用对象的set方法。
	 * 
	 * @param obj
	 *            需要反射的对象。
	 * @param name
	 *            对象的属性名
	 * @param values
	 *            需要set的值
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void setMethodInvoke(Object obj, String name, Object... values) {
		String setMethod = "set" + StringUtilTools.toUpperCaseFirstOne(name);
		Class<? extends Object> objClazz = obj.getClass();
		try {
			Method method = objClazz.getMethod(setMethod, objClazz.getDeclaredField(name).getType());
			if (null == values) {
				values = new Object[] {};
			}
			method.invoke(obj, values);
		} catch (NoSuchFieldException e) {
			info(clazz, "============ Not found field " + name + "==============");
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			info(clazz, "============ Not found method " + setMethod + "==============");
		}
	}

	/**
	 * 调用对象的get方法
	 * 
	 * @param obj
	 *            需要反射的对象
	 * @param name
	 *            对象的属性名
	 * @return Object 返回对象get方法返回的对象。
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Object getMethodInvoke(Object obj, String name) {
		if (null != name && !"".equals(name)) {
			String getMethod = "get" + StringUtilTools.toUpperCaseFirstOne(name);
			Class<? extends Object> clazz = obj.getClass();
			Object object = null;
			try {
				Method method = clazz.getMethod(getMethod, new Class[] {});
				object = method.invoke(obj, new Class[] {});
			} catch (Exception e) {
				e.printStackTrace();
			}
			return object;
		}
		return null;
	}

	/**
	 * 获得对象的所有属性
	 * 
	 * @param object
	 *            需要反射的对象
	 * @return 对象的所有属性数组。
	 */
	@SuppressWarnings("rawtypes")
	public static Field[] getObjectFields(Object object) {
		Class<? extends Object> clazz = object.getClass();
		return clazz.getDeclaredFields();
	}

	/**
	 * 获得对象的所有方法
	 * 
	 * @param object
	 *            需要反射的对象
	 * @return 对象的所有方法数组。
	 */
	@SuppressWarnings("rawtypes")
	public static Method[] getObjectMethods(Object object) {
		Class<? extends Object> clazz = object.getClass();
		return clazz.getDeclaredMethods();
	}

	/**
	 * <pre>
	 * 获得对象Class名
	 * </pre>
	 * 
	 * @param obj
	 *            对象
	 * @return String 对象类型名
	 */
	public static String getObjectName(Object obj) {
		return obj.getClass().getName();
	}

	/**
	 * <pre>
	 * 根据对象类型名生成一个新的对象
	 * </pre>
	 * 
	 * @param className
	 *            对象类型名
	 * @return Object 新对象
	 */
	public static Object newInstance(String className) {
		try {
			return Class.forName(className).newInstance();
		} catch (Exception e) {
			debug(clazz, e);
			return null;
		}
	}

	/**
	 * <pre>
	 * 根据对象生成一个新的对象.
	 * 相当于把一个对象复制了一份，但是没有原对象的初始设置
	 * </pre>
	 * 
	 * @param object
	 *            需要生成的对象
	 * @return Object 新对象
	 */
	public static Object newInstance(Object object) {
		try {
			return Class.forName(getObjectName(object)).newInstance();
		} catch (Exception e) {
			debug(clazz, e);
			return null;
		}
	}

	/**
	 * 功能描述：判断是否为整数
	 * 
	 * @param object
	 *            Object 传入的对象
	 * @return boolean 是整数返回true,否则返回false
	 */
	public static boolean isInteger(Object object) {
		return relace(object, BaseRegex.IS_INTEGER.getValue());
	}

	/**
	 * 功能描述：判断是否为浮点数，包括double和float
	 * 
	 * @param object
	 *            Object 传入的字符串
	 * @return boolean 是浮点数返回true,否则返回false
	 */
	public static boolean isDouble(Object object) {
		return relace(object, BaseRegex.IS_DOUBLE.getValue());
	}

	/**
	 * 功能描述：判断是否为字符串
	 * 
	 * @param object
	 *            Object 传入的字符串
	 * @return boolean 是字符串返回true,否则返回false
	 */
	public static boolean isString(Object object) {
		return relace(object, BaseRegex.IS_STRING.getValue());
	}

}
